﻿using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using Microsoft.CSharp;
using Microsoft.VisualBasic;
using Microsoft.JScript;
using System.Text;
using System.Reflection; //加入引用的。
//这个示例演示如何使用System.CodeDom来建立一个HELLO World程序,将会根据用户的选择动态代码生成及编译的C#,VB,JScript版本的程序集
namespace CodeDOMTest
{

    public class CodeDomExampleForm : System.Windows.Forms.Form
    {
        private System.Windows.Forms.Button run_button = new System.Windows.Forms.Button();
        private System.Windows.Forms.Button compile_button = new System.Windows.Forms.Button();
        private System.Windows.Forms.Button generate_button = new System.Windows.Forms.Button();
        private System.Windows.Forms.TextBox textBox1 = new System.Windows.Forms.TextBox();
        private System.Windows.Forms.ComboBox comboBox1 = new System.Windows.Forms.ComboBox();
        private System.Windows.Forms.Label label1 = new System.Windows.Forms.Label();

        private void generate_button_Click(object sender, System.EventArgs e)
        {
            CodeDomProvider provider = GetCurrentProvider();
            CodeDomExample.GenerateCode(provider, CodeDomExample.BuildHelloWorldGraph());

            StreamReader sr = new StreamReader("MyHello.cs");
            textBox1.Text = sr.ReadToEnd();
            sr.Close();
        }
        private void compile_button_Click(object sender, System.EventArgs e)
        {
            CodeDomProvider provider = GetCurrentProvider();
            CompilerResults cr = CodeDomExample.CompileCode(provider, "MyHello.cs");
            if (cr.Errors.Count > 0)
            {
                textBox1.Text = "编译文件出错： " + cr.PathToAssembly + ": /r/n";
                foreach (CompilerError ce in cr.Errors)
                    textBox1.AppendText(ce.ToString() + "/r/n");
                run_button.Enabled = false;
            }
            else
            {
                textBox1.Text = cr.PathToAssembly + " 编译成功";
                run_button.Enabled = true;
            }
        }
        private void run_button_Click(object sender, System.EventArgs e)
        {
            Process.Start("MyHello.exe");
        }

        /// <summary>
        /// 根据用户的选择返回不同语言的代码生成器
        /// </summary>
        /// <returns></returns>
        private CodeDomProvider GetCurrentProvider()
        {
            CodeDomProvider provider;
            switch ((string)this.comboBox1.SelectedItem)
            {
                case "CSharp":
                    provider = new CSharpCodeProvider();
                    break;
                case "Visual Basic":
                    provider = new VBCodeProvider();
                    break;
                case "JScript":
                    provider = new JScriptCodeProvider();
                    break;
                default:
                    provider = new CSharpCodeProvider();
                    break;
            }
            return provider;
        }

        public CodeDomExampleForm()
        {
            this.SuspendLayout();
            this.label1.Location = new System.Drawing.Point(395, 20);
            this.label1.Size = new Size(180, 22);
            this.label1.Text = "Select a programming language:";
            this.comboBox1.Location = new System.Drawing.Point(560, 16);
            this.comboBox1.Size = new Size(190, 23);
            this.comboBox1.Name = "comboBox1";
            this.comboBox1.Items.AddRange(new string[] { "CSharp", "Visual Basic", "JScript" });
            this.comboBox1.Anchor = System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right | System.Windows.Forms.AnchorStyles.Top;
            this.comboBox1.SelectedIndex = 0;
            this.generate_button.Location = new System.Drawing.Point(8, 16);
            this.generate_button.Name = "generate_button";
            this.generate_button.Size = new System.Drawing.Size(120, 23);
            this.generate_button.Text = "Generate Code";
            this.generate_button.Click += new System.EventHandler(this.generate_button_Click);

            this.compile_button.Location = new System.Drawing.Point(136, 16);
            this.compile_button.Name = "compile_button";
            this.compile_button.Size = new System.Drawing.Size(120, 23);
            this.compile_button.Text = "Compile";
            this.compile_button.Click += new System.EventHandler(this.compile_button_Click);

            this.run_button.Enabled = false;
            this.run_button.Location = new System.Drawing.Point(264, 16);
            this.run_button.Name = "run_button";
            this.run_button.Size = new System.Drawing.Size(120, 23);
            this.run_button.Text = "Run";
            this.run_button.Click += new System.EventHandler(this.run_button_Click);

            this.textBox1.Anchor = (((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
             | System.Windows.Forms.AnchorStyles.Left)
             | System.Windows.Forms.AnchorStyles.Right);
            this.textBox1.Location = new System.Drawing.Point(8, 48);
            this.textBox1.Multiline = true;
            this.textBox1.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
            this.textBox1.Name = "textBox1";
            this.textBox1.Size = new System.Drawing.Size(744, 280);
            this.textBox1.Text = "";
            // CodeDomExampleForm            
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.ClientSize = new System.Drawing.Size(768, 340);
            this.MinimumSize = new System.Drawing.Size(750, 340);
            this.Controls.AddRange(new System.Windows.Forms.Control[] { this.textBox1, this.run_button, this.compile_button, this.generate_button, this.comboBox1, this.label1 });
            this.Name = "CodeDomExampleForm";
            this.Text = "CodeDom Hello World Example";
            this.ResumeLayout(false);
        }
        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
        }
        private void InitializeComponent()
        {
            this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
            this.ClientSize = new System.Drawing.Size(448, 269);
            this.Name = "CodeDomExampleForm";
        }
        [STAThread]
        static void Main()
        {

         










           // Application.Run(new CodeDomExampleForm());
        }
    }
    public class CodeDomExample
    {
        public static CodeCompileUnit BuildHelloWorldGraph()
        {
            //建立一个代码容器
            //CodeCompileUnit 包含以下几个集合：可以存储包含 CodeDOM 源代码图形的 CodeNamespace 对象的集合、
            //项目引用的程序集的集合，以及项目程序集的属性集合。
            CodeCompileUnit CompileUnit = new CodeCompileUnit();
            // 声明一个名称空间
            CodeNamespace MySample = new CodeNamespace("MySample");
            // 将名称空间加入到代码容器
            CompileUnit.Namespaces.Add(MySample);

            // 导入一个名称空间
            MySample.Imports.Add(new CodeNamespaceImport("System"));
            // 声明一个类型
            CodeTypeDeclaration Hello = new CodeTypeDeclaration("Hello");
            // 将类型加入到容器的类型集合中
            MySample.Types.Add(Hello);

            // 构造函数(并非必须)
            CodeConstructor con = new CodeConstructor();
            con.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            Hello.Members.Add(con);
            // 表示可执行文件的入口点方法,也就是一个程序的入口
            CodeEntryPointMethod Start = new CodeEntryPointMethod();
            // 建立一个代码调用的表达式
            CodeMethodInvokeExpression cs1 = new CodeMethodInvokeExpression(
                // 调用方法. System.Console.WriteLine 
             new CodeTypeReferenceExpression("System.Console"), "WriteLine",
                // 给方法传一个基元数据类型的值
             new CodePrimitiveExpression("Hello World!"));
            // 将方法加入到方法中
            Start.Statements.Add(new CodeExpressionStatement(cs1));
            CodeMethodInvokeExpression cs2 = new CodeMethodInvokeExpression();
            CodeMethodReferenceExpression cmr = new CodeMethodReferenceExpression();
            cmr.MethodName = "SayHell";
            cs2.Method = cmr;

            Start.Statements.Add(new CodeExpressionStatement(cs2));
            // 将方法加入到类型中
            Hello.Members.Add(Start);
            // 成员函数SayHello,有参数,无返回值
            //   public bool SayHello(string input) 
            //   {
            //    Console.WriteLine(input);
            //    return false;
            //   }
            CodeMemberMethod cm = new CodeMemberMethod();
            cm.Name = "SayHello";

            cm.ReturnType = new CodeTypeReference(typeof(bool));
            cm.Attributes = MemberAttributes.Public | MemberAttributes.Final | MemberAttributes.Static;
            cm.Parameters.Add(
             new CodeParameterDeclarationExpression(
             typeof(string), "input"));
            cm.Statements.Add(
             new CodeMethodInvokeExpression(
             new CodeSnippetExpression("Console"), "WriteLine",
             new CodeArgumentReferenceExpression("input")));
            cm.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(false)));
            Hello.Members.Add(cm);
            return CompileUnit;
        }
        public static void GenerateCode(CodeDomProvider provider, CodeCompileUnit compileunit)
        {
            //获得生成代码的接口
            //ICodeGenerator gen = provider.CreateGenerator();
            //// 输出到文件
            //IndentedTextWriter tw = new IndentedTextWriter(new StreamWriter("MyHello.cs", false), "    ");
            //// 使用代码生成接口产生源代码.
            //gen.GenerateCodeFromCompileUnit(compileunit, tw, new CodeGeneratorOptions());

            //tw.Close();
        }
        public static CompilerResults CompileCode(CodeDomProvider provider, string filepath)
        {
            //// 获得编译器.       
            //ICodeCompiler compiler = provider.CreateCompiler();
            ////配置编译参数。将SYSTEM。DLL引用进来，同时明确生成的代码为EXE

            //CompilerParameters cp = new CompilerParameters(new string[] { "System.dll" }, filepath.Substring(0, filepath.LastIndexOf(".") + 1) + "exe", false);

            //cp.GenerateExecutable = true;
            //// 调用编译器
            //CompilerResults cr = compiler.CompileAssemblyFromFile(cp, filepath);

            //return cr;
            return null;
        }
    }
}